package oakclub.service;

import oakclub.global.Config;
import oakclub.utility.SocketUtility;
import oakclub.utility.UIDUtility;
import oakclub.utility.XmlUtility;
import org.w3c.dom.Document;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

public class JabberService
{
    private final String host = Config.get("ejabberd.host");
    private final int port = Integer.parseInt(Config.get("ejabberd.port"));
    private final String vhost = Config.get("ejabberd.vhost");

    private final int WAIT_RESPONSE = 3000; // in milliseconds

    private enum ResponseType
    {
        SUCCESS("result"), FAIL("error");

        private final String val;

        private ResponseType(String val)
        {
            this.val = val;
        }

        public String val()
        {
            return this.val;
        }
    }

    private enum CommandType
    {
        GET("get"), SET("set");

        private final String val;

        private CommandType(String val)
        {
            this.val = val;
        }

        public String val()
        {
            return this.val;
        }
    }

    private enum Command
    {
        REGISTER("jabber:iq:register");

        private final String val;

        private Command(String val)
        {
            this.val = val;
        }

        public String val()
        {
            return this.val;
        }
    }

    private final String XML_INIT = "<stream:stream to='%s' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>";
    private final String XML_COMMAND = "<iq type='%s' xml:lang='en' id='%s' to='%s'><query xmlns='%s'>%s</query></iq>";

    private void send(Command command, CommandType type, Map<String, String> params) throws Exception
    {
        Socket socket = SocketUtility.connect(this.host, this.port);
        BufferedWriter writer = SocketUtility.getWriter(socket);
        BufferedReader reader = SocketUtility.getReader(socket);

        // init
        SocketUtility.write(writer, String.format(this.XML_INIT, this.vhost));
        SocketUtility.read(reader, this.WAIT_RESPONSE);

        // send command
        String strParams = "";
        for(Map.Entry<String, String> entry : params.entrySet())
        {
            String key = entry.getKey();
            String value = entry.getValue();
            strParams += String.format("<%s>%s</%s>", key, value, key);
        }
        SocketUtility.write(writer, String.format(this.XML_COMMAND, type, UIDUtility.genUID(), this.vhost, command, strParams));
        String response = SocketUtility.read(reader, this.WAIT_RESPONSE);

        // close socket
        SocketUtility.close(socket);

        // parse response
        Document document = XmlUtility.parse(response);
        String responseType = document.getDocumentElement().getAttribute("type");
        if(responseType.equals(ResponseType.FAIL.val()))
        {
            throw new IllegalArgumentException(response);
        }
    }

    public void registerAccount(String username, String password) throws Exception
    {
        Map<String, String> params = new HashMap<>();
        params.put("username", username);
        params.put("password", password);
        this.send(Command.REGISTER, CommandType.SET, params);
    }
}
